package com.studerb.service.interfaces;

import java.util.List;

import com.studerb.exceptions.ServiceException;
import com.studerb.model.Server;

/**
 * Interface for the Server Service and {@link com.studerb.model.Server Server}
 * model. Implementations should send {@link com.studerb.events.ServerEvent
 * ServerEvent} events upon adding, deleting, and updating servers.
 * 
 * @see com.studerb.model.Server
 * @see com.studerb.events.ServerEvent
 */
public interface IServerService extends IService {

	/**
	 * Add a server to the database (and also the serverService list of servers)
	 * if this server is set to be the master server, then the previous master
	 * server is replaced. Also, if this is the first master then this becomes
	 * master by default
	 *<p>
	 * Publishes a {@link com.studerb.events.ServerEvent ServerEvent} of type
	 * {@link com.studerb.events.ServerEvent.EventType.ADDED ADDED}.
	 * 
	 * @param server
	 *            - {@link com.studerb.model.Server server} to add
	 */
	void addServer(Server server) throws ServiceException;

	/**
	 * Threads that call this method will be blocked until they are interrupted
	 * OR until a master server is available
	 * 
	 * @throws InterruptedException
	 * @see com.studerb.service.interfaces.IServerService#blockOnMasterServer()
	 */
	void awaitMasterServer() throws InterruptedException;

	/**
	 * Delete a server If there are more than one server and one tries to delete
	 * master server an exception is thrown.
	 * <p>
	 * Publishes a {@link com.studerb.events.ServerEvent ServerEvent} of type
	 * {@link com.studerb.events.ServerEvent.EventType.DELETED DELETED}.
	 * 
	 * @param server
	 *            - the server to delete
	 * @throws ServiceException
	 *             when attempting to delete the master server - must first
	 *             explicitly update to a new master server if there are other
	 *             servers left in the list
	 */
	void deleteServer(Server server);

	/**
	 * Get the current master server
	 * 
	 * @return server that is currently the 'master server' or null if there is
	 *         no master server (and by extension, no servers at all)
	 * @throws CloneNotSupportedException
	 */
	Server getMasterServer();

	/**
	 * Obtain the max possible number of connections, or essentially the sum of
	 * each defined server's max connections attribute
	 * 
	 * @return the maximum possible number of connections -
	 */
	int getMaxConnections();

	/**
	 * Obtain list of defined servers. By contract servers within the list
	 * should only be modified through public members of this service.
	 * 
	 * @return an unmodifiable (read-only) list of
	 *         {@link com.studerb.model.Server server }
	 */
	List<Server> getServers();

	/**
	 * Checks if there is currently a master server defined.
	 * 
	 * @return true if there is master server, false if not
	 */
	boolean isMasterServerDefined();

	/**
	 * Test if the the server is able to connect successfully to its nntp server
	 * 
	 * @param server
	 *            Server {@link com.studerb.model.Server Server} to test using a
	 *            basic command. No need for a connection pool
	 * @return True if the server can connect and successfully authenticate
	 *         using the server's attributes
	 */
	boolean testServer(Server server);

	/**
	 * Update a server's attributes. Modifying the status of master server
	 * should be taken care of in separate routines
	 * <p>
	 * Implementations should publish a {@link com.studerb.events.ServerEvent
	 * ServerEvent} of type
	 * {@link com.studerb.events.ServerEvent.EventType.UPDATED UPDATED}.
	 * 
	 * @param server
	 * @throws ServiceException
	 *             on errors related to changing master server statuses
	 */
	void updateServer(Server server) throws ServiceException;
}
